package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.CommonCodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.Product;
import cn.wolfcode.domain.SeckillProduct;
import cn.wolfcode.domain.SeckillProductVo;
import cn.wolfcode.feign.ProductApiFeign;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.ISeckillProductService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;


@Service
@Slf4j
public class SeckillProductServiceImpl implements ISeckillProductService {
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private ProductApiFeign productApiFeign;

    @Override
    public List<SeckillProductVo> selectByTime(Integer time) {
        // 创建返回的 vos 集合
        List<SeckillProductVo> vos = new ArrayList<>();
        List<SeckillProduct> seckillProducts = seckillProductMapper.queryCurrentlySeckillProduct(time);
        if (seckillProducts == null || seckillProducts.size() == 0) {
            return null;
        }
        // 获取 秒杀 商品的 ids集合
        List<Long> ids = new ArrayList<>();
        if (seckillProducts.size() >=0 ){
            for (SeckillProduct seckillProduct : seckillProducts) {
                ids.add(seckillProduct.getProductId());
            }
        }

        // 根据ids 集合, 查询商品数据
        Result<List<Product>> result = productApiFeign.getByIds(ids);
        List<Product> products = result.getData();
        // 聚合
        Map<Long,Product> map = new HashMap<>();
        if (products != null && products.size() > 0){
            for (Product product : products) {
                map.put(product.getId(),product);
            }
        }

        for (SeckillProduct seckillProduct : seckillProducts) {
            SeckillProductVo vo = new SeckillProductVo();
            Product product = map.get(seckillProduct.getProductId());
            BeanUtils.copyProperties(product,vo);
            BeanUtils.copyProperties(seckillProduct,vo);
            vo.setCurrentCount(seckillProduct.getStockCount()); // 设置库存
            vos.add(vo);
        }

        return vos;
    }

    @Override
    public List<SeckillProductVo> queryByTime(int time) {
        List<SeckillProductVo> vos = new ArrayList<>();
        // 查询redis中的所有商品
        List<Object> voStrs = redisTemplate.opsForHash().values(SeckillRedisKey.SECKILL_PRODUCT_LIST.getRealKey(time + ""));
        if (voStrs != null && voStrs.size() > 0) {
            for (Object voStr : voStrs) {
                // 将在redis 中获取到的元素转换为 json格式, 并进行对象的转换
                SeckillProductVo seckillProductVo = JSON.parseObject(voStr + "", SeckillProductVo.class);
                vos.add(seckillProductVo);
            }
        }
        return vos;
    }

    @Override
    public SeckillProductVo find(Integer time, Long seckillId) {
        // 参数校验
        if (time == null || seckillId == null || time < 0 || seckillId <0){
            throw new BusinessException(CommonCodeMsg.ILLEGAL_OPERATION);
        }
        // 去redis中查询对应的商品信息
        Object voStr = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_PRODUCT_LIST.getRealKey(time + ""), seckillId.toString());
        if (voStr == null){
            throw new BusinessException(CommonCodeMsg.ILLEGAL_OPERATION);
        }
        // 转换为vo对象
        SeckillProductVo vo = JSON.parseObject(voStr + "", SeckillProductVo.class);

        return vo;
    }

    @Override
    public int descStock(Long seckillId) {
        return seckillProductMapper.decrStock(seckillId);
    }

    @Override
    public void asysBackRedisStockCount(Long seckillId, Integer time) {
        // 回补实现逻辑
        // 1.查看当前数据库的库存数(因此此时, 事务的原因,失败事务回滚,mysql的数据不会变动)
        int stockCount = seckillProductMapper.getStockCount(seckillId);
        // 2.将当前库存数存储到redis中
        redisTemplate.opsForHash().put(SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(time.toString()),seckillId.toString(),stockCount + "");

    }

    @Override
    public void incrStockCount(Long seckillId) {
        seckillProductMapper.incrStock(seckillId);
    }
}
